diff --git a/Cargo.lock b/Cargo.lock index f720dc4..9223a9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,9 +25,7 @@ checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483" [[package]] name = "anchor-attribute-access-control" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ff7b54a5d232ce177fb5e1d42bb767678e5df0434b205a045afa8fc7a83a23" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -39,9 +37,7 @@ dependencies = [ [[package]] name = "anchor-attribute-account" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2c53504cae7e67cd4d7a2d6db6828293923c0a0d80e8ae29e67bf517548d6e" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -54,9 +50,7 @@ dependencies = [ [[package]] name = "anchor-attribute-error" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8341b2661f13ca6e4dfb55e21f49908774d9fb915c56dbd7b804668c3eb53380" +version = "0.17.0" dependencies = [ "anchor-syn", "proc-macro2", @@ -66,9 +60,7 @@ dependencies = [ [[package]] name = "anchor-attribute-event" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5e4e868c019d872baa669b43796a877e6a66da4a286a1b8467ba747428804d" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -79,9 +71,7 @@ dependencies = [ [[package]] name = "anchor-attribute-interface" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db9d1de704bf2845d9edc7fe368a48943b672f2e770251c4d929d6712bac367d" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -93,9 +83,7 @@ dependencies = [ [[package]] name = "anchor-attribute-program" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f035ee71ffa1db5f06694a650aa61ba4265f9fa1263fed3b744b2cd8a31f448a" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -106,9 +94,7 @@ dependencies = [ [[package]] name = "anchor-attribute-state" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a2bfe33f0fc0aeffe01dda3aa36417eb96ebcfc39dfdb003ef968d5ed9a70f" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -119,9 +105,7 @@ dependencies = [ [[package]] name = "anchor-derive-accounts" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffb0562db113cd2491e825e0f4df8d050dc14371dec7cccf757efcf86445451" +version = "0.17.0" dependencies = [ "anchor-syn", "anyhow", @@ -132,9 +116,7 @@ dependencies = [ [[package]] name = "anchor-lang" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd220aca840a0067d43da61e802a5e4ac13582f0baef7aa33c79d42a0110086" +version = "0.17.0" dependencies = [ "anchor-attribute-access-control", "anchor-attribute-account", @@ -153,22 +135,19 @@ dependencies = [ [[package]] name = "anchor-spl" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f34afdc6678b3c2563403f6ca2a6d59b2407cd3334757e2761c4776e0339764" +version = "0.17.0" dependencies = [ "anchor-lang", "lazy_static", "serum_dex", "solana-program", + "spl-associated-token-account", "spl-token", ] [[package]] name = "anchor-syn" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93cade4d95b7edd8d6be4e8243b935e26dee6eb1a50bd226392cefd0a31e682c" +version = "0.17.0" dependencies = [ "anyhow", "bs58 0.3.1", @@ -991,8 +970,7 @@ dependencies = [ [[package]] name = "serum_dex" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02705854bae4622e552346c8edd43ab90c7425da35d63d2c689f39238f8d8b25" +source = "git+https://github.com/project-serum/serum-dex?rev=1be91f2#1be91f2863d8ecede32daaae7e768034e24bbc79" dependencies = [ "arrayref", "bincode", @@ -1128,6 +1106,16 @@ dependencies = [ "syn", ] +[[package]] +name = "spl-associated-token-account" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393e2240d521c3dd770806bff25c2c00d761ac962be106e14e22dd912007f428" +dependencies = [ + "solana-program", + "spl-token", +] + [[package]] name = "spl-token" version = "3.2.0" diff --git a/package.json b/package.json index 14517fc..5ffc20f 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "dependencies": { - "@project-serum/anchor": "^0.16.1" + "@project-serum/anchor": "^0.17.1-beta.1", + "@solana/spl-token": "^0.1.8" }, "devDependencies": { + "@types/mocha": "^9.0.0", "chai": "^4.3.4", "mocha": "^9.0.3", "ts-mocha": "^8.0.0", - "@types/mocha": "^9.0.0", "typescript": "^4.3.5" } } diff --git a/programs/governance-registry/Cargo.toml b/programs/governance-registry/Cargo.toml index 38da5e2..cb2c6e6 100644 --- a/programs/governance-registry/Cargo.toml +++ b/programs/governance-registry/Cargo.toml @@ -15,5 +15,6 @@ cpi = ["no-entrypoint"] default = [] [dependencies] -anchor-lang = "0.16.1" -anchor-spl = "0.16.1" +# TODO: use versions after next Anchor publish. +anchor-lang = { git = "https://github.com/project-serum/anchor" } +anchor-spl = { git = "https://github.com/project-serum/anchor" } diff --git a/programs/governance-registry/src/lib.rs b/programs/governance-registry/src/lib.rs index 27596b3..f67ae12 100644 --- a/programs/governance-registry/src/lib.rs +++ b/programs/governance-registry/src/lib.rs @@ -1,5 +1,8 @@ +use anchor_lang::__private::bytemuck::Zeroable; use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{self, Mint, Token, TokenAccount}; +use std::mem::size_of; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); @@ -7,63 +10,94 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); pub mod governance_registry { use super::*; - /// Creates a new voting registrar. + /// Creates a new voting registrar. There can only be a single regsitrar + /// per governance realm. pub fn init_registrar( ctx: Context, - _voting_mint_decimals: u8, registrar_bump: u8, voting_mint_bump: u8, + _voting_mint_decimals: u8, ) -> Result<()> { - let registrar = &mut ctx.accounts.registrar; + let registrar = &mut ctx.accounts.registrar.load_init()?; registrar.registrar_bump = registrar_bump; registrar.voting_mint_bump = voting_mint_bump; registrar.realm = ctx.accounts.realm.key(); registrar.voting_mint = ctx.accounts.voting_mint.key(); registrar.authority = ctx.accounts.authority.key(); - if true { - panic!("HELLO WORLD"); - } + Ok(()) } - /// Creates a new voter account. + /// Creates a new voter account. There can only be a single voter per + /// user wallet. pub fn init_voter(ctx: Context, voter_bump: u8) -> Result<()> { - let voter = &mut ctx.accounts.voter; + let voter = &mut ctx.accounts.voter.load_mut()?; voter.voter_bump = voter_bump; voter.authority = ctx.accounts.authority.key(); voter.registrar = ctx.accounts.registrar.key(); - voter.rights_outstanding = 0; Ok(()) } - /// Creates a new exchange rate for a given mint. The exchange rate - /// allows one to deposit one token into the registrar and receive voting - /// tokens in response. Only the registrar authority can invoke this. - pub fn add_exchange_rate( - ctx: Context, - rate: u64, - rate_bump: u8, - vault_bump: u8, - ) -> Result<()> { - require!(rate > 0, InvalidRate); - - let rate = &mut ctx.accounts.exchange_rate; - rate.deposit_mint = ctx.accounts.deposit_mint.key(); - rate.rate_bump = rate_bump; - rate.vault_bump = vault_bump; - + /// Creates a new exchange rate for a given mint. This allows a voter to + /// deposit the mint in exchange for vTokens. There can only be a single + /// exchange rate per mint. + pub fn add_exchange_rate(ctx: Context, er: ExchangeRateEntry) -> Result<()> { + require!(er.rate > 0, InvalidRate); + let registrar = &mut ctx.accounts.registrar.load_mut()?; + let idx = registrar + .rates + .iter() + .position(|r| !r.is_used) + .ok_or(ErrorCode::RatesFull)?; + registrar.rates[idx] = er; Ok(()) } - /// Deposits tokens into the registrar in exchange for voting rights that - /// can be used with a DAO. - pub fn mint_voting_rights(ctx: Context, amount: u64) -> Result<()> { - // Deposit tokens into the registrar. - token::transfer((&*ctx.accounts).into(), amount)?; + /// Deposits tokens into the registrar in exchange for *frozen* voting + /// tokens. These tokens are not used for anything other than displaying + /// the amount in walletes. + pub fn deposit(ctx: Context, amount: u64) -> Result<()> { + let registrar = &mut ctx.accounts.registrar.load()?; + let voter = &mut ctx.accounts.voter.load_mut()?; + + // Get the exchange rate entry associated with this deposit. + let er_idx = registrar + .rates + .iter() + .position(|r| r.mint == ctx.accounts.deposit_mint.key()) + .ok_or(ErrorCode::ExchangeRateEntryNotFound)?; + let er_entry = registrar.rates[er_idx]; + + // Get the deposit entry associated with this deposit. + let deposit_entry = { + match voter.deposits.iter().position(|deposit_entry| { + registrar.rates[deposit_entry.rate_idx as usize].mint + == ctx.accounts.deposit_mint.key() + }) { + // Lazily instantiate the deposit if needed. + None => { + let free_entry_idx = voter + .deposits + .iter() + .position(|deposit_entry| !deposit_entry.is_used) + .ok_or(ErrorCode::DepositEntryFull)?; + let entry = &mut voter.deposits[free_entry_idx]; + entry.is_used = true; + entry.rate_idx = free_entry_idx as u8; + entry + } + // Use the existing deposit. + Some(e) => &mut voter.deposits[e], + } + }; + deposit_entry.amount += amount; // Calculate the amount of voting tokens to mint. - let scaled_amount = { amount }; + let scaled_amount = er_entry.rate * amount; + + // Deposit tokens into the registrar. + token::transfer((&*ctx.accounts).into(), amount)?; // Mint vote tokens to the depositor. token::mint_to((&*ctx.accounts).into(), scaled_amount)?; @@ -71,8 +105,16 @@ pub mod governance_registry { Ok(()) } - /// Updates the Voter's voting rights by decaying locked deposits. - pub fn decay_voting_rights(ctx: Context) -> Result<()> { + /// Withdraws tokens from a deposit entry, if they are unlocked according + /// to a vesting schedule. + pub fn withdraw(ctx: Context, amount: u64) -> Result<()> { + // todo + Ok(()) + } + + /// Updates a vesting schedule. Can only increase the lockup time. If all + /// tokens are unlocked, then the period count can also be updated. + pub fn update_schedule(ctx: Context) -> Result<()> { // todo Ok(()) } @@ -81,15 +123,16 @@ pub mod governance_registry { // Contexts. #[derive(Accounts)] -#[instruction(voting_mint_decimals: u8, registrar_bump: u8, voting_mint_bump: u8)] +#[instruction(registrar_bump: u8, voting_mint_bump: u8, voting_mint_decimals: u8)] pub struct InitRegistrar<'info> { #[account( init, seeds = [realm.key().as_ref()], bump = registrar_bump, payer = payer, + space = 8 + size_of::() )] - registrar: Account<'info, Registrar>, + registrar: AccountLoader<'info, Registrar>, #[account( init, seeds = [registrar.key().as_ref()], @@ -115,52 +158,42 @@ pub struct InitVoter<'info> { seeds = [registrar.key().as_ref(), authority.key().as_ref()], bump = voter_bump, payer = authority, + space = 8 + size_of::() )] - voter: Account<'info, Voter>, - registrar: Account<'info, Registrar>, + voter: AccountLoader<'info, Voter>, + registrar: AccountLoader<'info, Registrar>, authority: Signer<'info>, system_program: Program<'info, System>, } #[derive(Accounts)] -#[instruction(rate_bump: u8, vault_bump: u8)] +#[instruction(rate: ExchangeRateEntry)] pub struct AddExchangeRate<'info> { #[account( init, - seeds = [b"exchange-rate", registrar.key().as_ref(), deposit_mint.key().as_ref()], - bump = rate_bump, payer = payer, - )] - exchange_rate: Account<'info, ExchangeRate>, - #[account( - init, - seeds = [b"exchange-vault", exchange_rate.key().as_ref()], - bump = vault_bump, - payer = payer, - token::authority = registrar, - token::mint = deposit_mint, + associated_token::authority = registrar, + associated_token::mint = deposit_mint, )] exchange_vault: Account<'info, TokenAccount>, deposit_mint: Account<'info, Mint>, #[account(has_one = authority)] - registrar: Account<'info, Registrar>, + registrar: AccountLoader<'info, Registrar>, authority: Signer<'info>, payer: Signer<'info>, rent: Sysvar<'info, Rent>, token_program: Program<'info, Token>, + associated_token_program: Program<'info, AssociatedToken>, system_program: Program<'info, System>, } #[derive(Accounts)] -pub struct MintVotingRights<'info> { +pub struct Deposit<'info> { + #[account(has_one = authority)] + voter: AccountLoader<'info, Voter>, #[account( - seeds = [b"exchange-rate", registrar.key().as_ref(), deposit_mint.key().as_ref()], - bump = exchange_rate.rate_bump, - )] - exchange_rate: Account<'info, ExchangeRate>, - #[account( - seeds = [b"exchange-vault", exchange_rate.key().as_ref()], - bump = exchange_rate.vault_bump, + associated_token::authority = registrar, + associated_token::mint = deposit_mint, )] exchange_vault: Account<'info, TokenAccount>, #[account( @@ -168,71 +201,83 @@ pub struct MintVotingRights<'info> { )] deposit_token: Account<'info, TokenAccount>, #[account( - constraint = registrar.voting_mint == voting_token.mint, + constraint = registrar.load()?.voting_mint == voting_token.mint, )] voting_token: Account<'info, TokenAccount>, authority: Signer<'info>, - registrar: Account<'info, Registrar>, + registrar: AccountLoader<'info, Registrar>, deposit_mint: Account<'info, Mint>, voting_mint: Account<'info, Mint>, token_program: Program<'info, Token>, } #[derive(Accounts)] -pub struct DecayVotingRights<'info> { - voter: Account<'info, Voter>, - deposit: Account<'info, VoterDeposit>, +pub struct Withdraw { + // todo +} + +#[derive(Accounts)] +pub struct UpdateSchedule { + // todo } // Accounts. /// Instance of a voting rights distributor. -#[account] -#[derive(Default)] +#[account(zero_copy)] pub struct Registrar { pub authority: Pubkey, pub realm: Pubkey, pub voting_mint: Pubkey, pub voting_mint_bump: u8, pub registrar_bump: u8, + pub rates: [ExchangeRateEntry; 32], } /// User account for minting voting rights. -#[account] -#[derive(Default)] +#[account(zero_copy)] pub struct Voter { pub authority: Pubkey, pub registrar: Pubkey, - pub rights_outstanding: u64, pub voter_bump: u8, -} - -pub struct Deposit { - pub mint_idx: u8, - pub lockup_years: u8, - pub amount: u64, -} - -/// Sub account for a -#[account] -pub struct VoterDeposit { - amount: u64, - exchange_rate: Pubkey, + pub deposits: [DepositEntry; 32], } /// Exchange rate for an asset that can be used to mint voting rights. -#[account] -#[derive(Default)] -pub struct ExchangeRate { - deposit_mint: Pubkey, - rate: u64, - rate_bump: u8, - vault_bump: u8, +#[zero_copy] +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct ExchangeRateEntry { + // True if the exchange rate entry is being used. + pub is_used: bool, + + pub mint: Pubkey, + pub rate: u64, +} + +unsafe impl Zeroable for ExchangeRateEntry {} + +#[zero_copy] +pub struct DepositEntry { + // True if the deposit entry is being used. + pub is_used: bool, + + // Points to the ExchangeRate this deposit uses. + pub rate_idx: u8, + pub amount: u64, // Locked state. - period_count: u64, - start_ts: i64, - end_ts: i64, + pub period_count: u64, + pub start_ts: i64, + pub end_ts: i64, +} + +impl DepositEntry { + /// Returns the voting power given by this deposit, scaled to account for + /// a lockup. + pub fn voting_power(&self) -> u64 { + let locked_multiplier = 1; // todo + self.amount * locked_multiplier + } } // Error. @@ -241,14 +286,19 @@ pub struct ExchangeRate { pub enum ErrorCode { #[msg("Exchange rate must be greater than zero")] InvalidRate, + #[msg("")] + RatesFull, + #[msg("")] + ExchangeRateEntryNotFound, + #[msg("")] + DepositEntryNotFound, + DepositEntryFull, } // CpiContext. -impl<'info> From<&MintVotingRights<'info>> - for CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> -{ - fn from(accs: &MintVotingRights<'info>) -> Self { +impl<'info> From<&Deposit<'info>> for CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { + fn from(accs: &Deposit<'info>) -> Self { let program = accs.token_program.to_account_info(); let accounts = token::Transfer { from: accs.deposit_token.to_account_info(), @@ -259,8 +309,8 @@ impl<'info> From<&MintVotingRights<'info>> } } -impl<'info> From<&MintVotingRights<'info>> for CpiContext<'_, '_, '_, 'info, token::MintTo<'info>> { - fn from(accs: &MintVotingRights<'info>) -> Self { +impl<'info> From<&Deposit<'info>> for CpiContext<'_, '_, '_, 'info, token::MintTo<'info>> { + fn from(accs: &Deposit<'info>) -> Self { let program = accs.token_program.to_account_info(); let accounts = token::MintTo { mint: accs.voting_mint.to_account_info(), diff --git a/tests/governance-registry.ts b/tests/governance-registry.ts index f63f768..c982dc4 100644 --- a/tests/governance-registry.ts +++ b/tests/governance-registry.ts @@ -1,17 +1,19 @@ import * as anchor from '@project-serum/anchor'; +import { Program } from '@project-serum/anchor'; import { PublicKey, Keypair, SystemProgram, SYSVAR_RENT_PUBKEY } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; +import { GovernanceRegistry } from '../target/types/governance_registry'; describe('voting-rights', () => { - - // Configure the client to use the local cluster. anchor.setProvider(anchor.Provider.env()); - const program = anchor.workspace.GovernanceRegistry; - const realm = Keypair.generate().publicKey; + const program = anchor.workspace.GovernanceRegistry as Program; + // Initialized variables shared across tests. + const realm = Keypair.generate().publicKey; const votingMintDecimals = 6; + // Uninitialized variables shared across tests. let registrar: PublicKey, votingMint: PublicKey, voter: PublicKey; let registrarBump: number, votingMintBump: number, voterBump: number; @@ -39,7 +41,7 @@ describe('voting-rights', () => { }); it('Initializes a registrar', async () => { - await program.rpc.initRegistrar(votingMintDecimals, registrarBump, votingMintBump, { + await program.rpc.initRegistrar(registrarBump, votingMintBump, votingMintDecimals, { accounts: { registrar, votingMint, diff --git a/yarn.lock b/yarn.lock index fbe014e..6f3b25b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,17 +2,17 @@ # yarn lockfile v1 -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": +"@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== dependencies: regenerator-runtime "^0.13.4" -"@project-serum/anchor@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.16.1.tgz#e044280e4534a966161a101619f5259252eda8ff" - integrity sha512-nbpxo5xgENkdDqfRBMMhCqicj9Mc3QcGFOy1cl5j7uYqvFjdOfkOMcP19sf6/m4wmgaclfiYfWeHALy7XDOubQ== +"@project-serum/anchor@^0.17.1-beta.1": + version "0.17.1-beta.1" + resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.17.1-beta.1.tgz#0532b4534c6a86e67e8530040c717979240f1dbe" + integrity sha512-W23rI48nNm6sM+3L6jUh4kSWh5cLJWwJHiohB2AnnG+9jYs/NSgCcope8dP0g2DeHITCo5E/VpZpZc4Fulqqpg== dependencies: "@project-serum/borsh" "^0.2.2" "@solana/web3.js" "^1.17.0" @@ -44,6 +44,18 @@ dependencies: buffer "~6.0.3" +"@solana/spl-token@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.1.8.tgz#f06e746341ef8d04165e21fc7f555492a2a0faa6" + integrity sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ== + dependencies: + "@babel/runtime" "^7.10.5" + "@solana/web3.js" "^1.21.0" + bn.js "^5.1.0" + buffer "6.0.3" + buffer-layout "^1.2.0" + dotenv "10.0.0" + "@solana/web3.js@^1.17.0": version "1.29.0" resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.29.0.tgz#61cb40e2190f13ae8084d20012cb81f8fade78fa" @@ -64,6 +76,26 @@ superstruct "^0.14.2" tweetnacl "^1.0.0" +"@solana/web3.js@^1.21.0": + version "1.29.2" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.29.2.tgz#05c162f477c226ee3211f8ee8c1c6d4203e08f54" + integrity sha512-gtoHzimv7upsKF2DIO4/vNfIMKN+cxSImBHvsdiMyp9IPqb8sctsHVU/+80xXl0JKXVKeairDv5RvVnesJYrtw== + dependencies: + "@babel/runtime" "^7.12.5" + "@solana/buffer-layout" "^3.0.0" + bn.js "^5.0.0" + borsh "^0.4.0" + bs58 "^4.0.1" + buffer "6.0.1" + cross-fetch "^3.1.4" + crypto-hash "^1.2.2" + jayson "^3.4.4" + js-sha3 "^0.8.0" + rpc-websockets "^7.4.2" + secp256k1 "^4.0.2" + superstruct "^0.14.2" + tweetnacl "^1.0.0" + "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -214,7 +246,7 @@ bn.js@^4.11.9: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.2: +bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== @@ -279,7 +311,7 @@ buffer@6.0.1: base64-js "^1.3.1" ieee754 "^1.2.1" -buffer@~6.0.3: +buffer@6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -434,6 +466,11 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dotenv@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + elliptic@^6.5.2: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"