Solana, Anchor 및 React 탐색기를 사용한 파생 주소(PDA)

주: 본고를 작성할 때(2021년 12월 13일, 월요일)까지 소라나testnet의 환경(수도꼭지/공중투하)에 문제가 있는 것 같습니다.선택기에서 devnet를 선택하거나 기본값이기 때문에 변경하지 마십시오.지갑을 지향devnet 네트워크로 바꾸는 것을 잊지 마세요.
주: 이 게시물의 모든 코드를 찾을 수 있습니다here.본문의 개념을 보여주는 시범here이 있다.

용례


다음 장면을 상상해 봅시다.사용자가 만들거나 주조한 기호화폐를 사용하는 dApp을 만들었습니다.테스트 목적에서 사용자가 스스로 영패를 공중으로 던지는 것을 허용하기를 원합니다. (테스트 환경에서)문제는 당신이 기호화폐를 주조했으니 더 많은 기호화폐를 주조하거나 양도할 권리가 있는 사람이 바로 당신입니다.이것은 당신이 이 조폐소와 거래하는 모든 거래에 서명해야 한다는 것을 의미한다.
또 다른 상황은 사용자가 다른 사용자와 어떤 상품을 교환하기를 원한다는 것이다.안전을 위해 거래된 물품은 특정한 임시 계좌(제3자 위탁 관리 계좌)에 넣고 제3자에게만 발급해야 하며 그들은 견적을 받아들일 수 있다.어려움은 위탁 관리 계좌가 사용자에게 속하면 그들이 기호화폐를 발급하기 위해 거래를 비준/서명해야 한다는 것이다.우리는 사용자가 프로젝트의 발표에 직접 참여하는 것을 원하지 않는다.
이 두 가지 상황에서 우리는 프로그램 소유자를 대표하여 거래에 서명할 수 있는'대리'가 필요하다.이를 위해서는 프로그램 파생 주소(PDA)가 필요합니다.
내가 위에서 묘사한 장면에서 우리는 사용해야 한다Cross-Program Invocations.이 두 가지 상황에서 우리는 Token Program와 상호작용을 할 것이다.공중 투하 상황에서 우리는 mint 더 많은 기존 기호화폐를 사용자에게 주고 두 번째 상황에서 우리는 transfer 기호화폐를 줄 것이다.
이 두 가지 상황에서 PDA는 우리를 대표하여 이 거래에 서명할 권리가 있다.

PDA의 정의


이 계정들은 프로그램이 가지고 있으며 다른 계정과 달리 개인 키의 통제를 받지 않는다.Pubkey::create_program_address 이러한 주소를 생성합니다.이 메서드는 프로그램 ID 해싱 피드를 사용하여 새 32바이트 주소를 만듭니다.변화(50%)가 있는데 이것은 ed25519 곡선의 점일 수 있다.이것은 이 주소와 연결된 개인 키가 있다는 것을 의미합니다.이 경우 Solana 프로그래밍 모델의 안전성이 손상될 수 있습니다.생성된 주소가 ed25519 곡선에 있으면 Pubkey::create_program_address 실패합니다.
일을 간소화하기 위해 방법Pubkey::find_program_address은 필요에 따라 여러 번create_program_address을 호출하여 우리가 효과적인 방법을 찾을 때까지 한다.

내부 작업 중인 PDA



PDA를 더 탐색하기 위해 농장 동물 거래 앱을 개발하기로 했다.네가 거래하는 동물은 기호화폐다.이 응용 프로그램에서 PDA는 두 가지 다른 사용 방식을 가지고 있다.첫 번째 방식은 위탁 계좌다.사용자는 그들이 제공한 지폐를 저장한다.만약 다른 사용자가 요약을 받아들이거나 요약을 발기한 사용자가 요약을 취소하기로 결정한다면 이 기호화폐는 방출될 것이다.이 두 가지 상황에서 계좌 자체는 목적지로의 이동에 서명할 권리가 있다.
주의: 코드 세션에 대해, 나는 관련 부분만 표시하고, 환매 프로토콜의 줄 번호를 연결할 것입니다.모든 코드를 찾을 수 있습니다.

여기 있다 계좌를 대신 관리하다.


우선, 우리는 주소를 내보내야 한다.이것은 우리의 위탁 계좌 가 될 것이다.
    const offer = anchor.web3.Keypair.generate();
    const [escrowedTokensOfOfferMaker, escrowedTokensOfOfferMakerBump] = await anchor.web3.PublicKey.findProgramAddress(
      [offer.publicKey.toBuffer()],
      program.programId
    )
우리는 요철을 저장해서, 이렇게 하면 호출 findProgrammAddress 방법을 통해 그것을 다시 계산할 필요도, 앞쪽에서 아래로 전달할 필요도 없다.contract / program에서는 이렇게 사용합니다code. 전체 파일을 찾을 수 있습니다.여기서 견적을 작성하고 있습니다.
    anchor_spl::token::transfer(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::Transfer {
                from: ctx
                    .accounts
                    .token_account_from_who_made_the_offer
                    .to_account_info(),
                to: ctx
                    .accounts
                    .escrowed_tokens_of_offer_maker
                    .to_account_info(),
                authority: ctx.accounts.who_made_the_offer.to_account_info(),
            },
        ),
        im_offering_this_much,
    )
우리는 가격을 제시한 계좌에서 위탁 관리 계좌로 기호화폐를 옮기고 있다.얼마나 옮길지 지정했어.
이때 우리는 오퍼를 받아들이거나 취소할 수 있다.취소의 경우here:
    // Transfer what's on the escrowed account to the offer reciever.
    anchor_spl::token::transfer(
        CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::Transfer {
                from: ctx
                    .accounts
                    .escrowed_tokens_of_offer_maker
                    .to_account_info(),
                to: ctx
                    .accounts
                    .where_the_escrowed_account_was_funded_from
                    .to_account_info(),
                authority: ctx
                    .accounts
                    .escrowed_tokens_of_offer_maker
                    .to_account_info(),
            },
            &[&[
                ctx.accounts.offer.key().as_ref(),
                &[ctx.accounts.offer.escrowed_tokens_of_offer_maker_bump],
            ]],
        ),
        ctx.accounts.escrowed_tokens_of_offer_maker.amount,
    )?;

    // Close the escrow account
    anchor_spl::token::close_account(CpiContext::new_with_signer(
        ctx.accounts.token_program.to_account_info(),
        anchor_spl::token::CloseAccount {
            account: ctx
                .accounts
                .escrowed_tokens_of_offer_maker
                .to_account_info(),
            destination: ctx.accounts.who_made_the_offer.to_account_info(),
            authority: ctx
                .accounts
                .escrowed_tokens_of_offer_maker
                .to_account_info(),
        },
        &[&[
            ctx.accounts.offer.key().as_ref(),
            &[ctx.accounts.offer.escrowed_tokens_of_offer_maker_bump],
        ]],
    ))
우리는 이 혜택을 발기한 계좌로 기호화폐를 보내고 있다.거래에 서명한 기구는 PDA입니다. 왜냐하면 기호화폐를 가지고 있기 때문입니다.우리도 더 이상 필요하지 않기 때문에 대리 관리 계좌를 닫고 있다.
마지막 관련 부분은 요약을 받은 기호화폐의'교환'이다.
        // Transfer token to who started the offer
        anchor_spl::token::transfer(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                anchor_spl::token::Transfer {
                    from: ctx
                        .accounts
                        .account_holding_what_receiver_will_give
                        .to_account_info(),
                    to: ctx
                        .accounts
                        .account_holding_what_maker_will_get
                        .to_account_info(),
                    authority: ctx.accounts.who_is_taking_the_offer.to_account_info(),
                },
            ),
            ctx.accounts.offer.amount_received_if_offer_accepted,
        )?;

        // Transfer what's on the escrowed account to the offer reciever.
        anchor_spl::token::transfer(
            CpiContext::new_with_signer(
                ctx.accounts.token_program.to_account_info(),
                anchor_spl::token::Transfer {
                    from: ctx
                        .accounts
                        .escrowed_tokens_of_offer_maker
                        .to_account_info(),
                    to: ctx
                        .accounts
                        .account_holding_what_receiver_will_get
                        .to_account_info(),
                    authority: ctx
                        .accounts
                        .escrowed_tokens_of_offer_maker
                        .to_account_info(),
                },
                &[&[
                    ctx.accounts.offer.key().as_ref(),
                    &[ctx.accounts.offer.escrowed_tokens_of_offer_maker_bump],
                ]],
            ),
            ctx.accounts.escrowed_tokens_of_offer_maker.amount,
        )?;

        // Close the escrow account
        anchor_spl::token::close_account(CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::CloseAccount {
                account: ctx
                    .accounts
                    .escrowed_tokens_of_offer_maker
                    .to_account_info(),
                destination: ctx.accounts.who_made_the_offer.to_account_info(),
                authority: ctx
                    .accounts
                    .escrowed_tokens_of_offer_maker
                    .to_account_info(),
            },
            &[&[
                ctx.accounts.offer.key().as_ref(),
                &[ctx.accounts.offer.escrowed_tokens_of_offer_maker_bump],
            ]],
        ))
우리가 이렇게 하는 것은 세 가지 절차다.우선, 우리는 원하는 토큰을 제시 가격을 제시한 사용자에게 보낼 것입니다.그리고 우리는 위탁 지폐를 요약을 받는 사용자에게 이전할 것이다.그리고 지난번에 캡처한 것과 같이, 우리는 더 이상 필요하지 않기 때문에 대리 계정을 닫을 것입니다.

섹션 공중 투하


응용 프로그램에서 PDA를 사용하는 또 다른 방법은 공중 투과입니다.이런 상황에서 우리는 사용자가 우리가 가지고 있는 유한한 수량의 물건(기호화폐)을 스스로 조폐(공중투하)할 수 있도록 허락하기를 희망한다.이러한 상황에서 PDA는 우리가 새 기호화폐의 주조에 서명하는 것을 대표할 권리가 있다.
이전과 마찬가지로 우리는 findProgramAddress를 사용하여 PDA를 획득했습니다.
    const cowSeed = Buffer.from(anchor.utils.bytes.utf8.encode("cow-mint-faucet"));
    const pigSeed = Buffer.from(anchor.utils.bytes.utf8.encode("pig-mint-faucet"));

    const [cowMintPda, cowMintPdaBump] = await anchor.web3.PublicKey.findProgramAddress(
      [cowSeed],
      program.programId);

    const [pigMintPda, pigMintPdaBump] = await anchor.web3.PublicKey.findProgramAddress(
      [pigSeed],
      program.programId);

띄우기 코드는 다음과 같이 간략화됩니다.
    anchor_spl::token::mint_to(
        CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::MintTo {
                mint: ctx.accounts.mint.to_account_info(),
                to: ctx.accounts.destination.to_account_info(),
                authority: ctx.accounts.mint.to_account_info(),
            },
            &[&[&mint_seed, &[mint_bump]]],
        ),
        amount,
    )?;
이전과 마찬가지로 여기서 주의해야 할 가장 중요한 점은 PDA 자체가 거래에 서명할 권리가 있다는 것이다.

종합하다.


프레젠테이션 어플리케이션 이 구축되었습니다.devnettestnet 모두 애플리케이션을 구축했습니다.페이지의 선택기를 사용하여 둘 사이를 변경할 수 있습니다. (만약 이렇게 한다면 가리키는 네트워크를 변경하는 것을 기억하십시오.)
만약 네가 SOL이 없다면, 너는 좀 공중 투하할 수 있다.이 밖에 농장 동물들을 공수해 거래를 시작할 수 있소.
주의: 20초 간격으로 나는 모든 사용자가 사용할 수 있는 완전한 제품 목록을 표시하기 위해 체인 밖 데이터베이스로 끌어올릴 것이다.

여기 있다 마지막 생각.


이것은 소라나의 또 하나의 재미있는 실험이다.나는 모든 물건을 체인에 유지하고 싶었지만, 결국은 모든 사용자가 그것을 사용할 수 있도록 체인 밖의 데이터베이스를 얻었다.나는 모든 혜택을 체인점에 두는 것을 탐색할 것이다.
전반적으로 나는 소라나와 함께 노는 시간을 즐겼다.나는 계속 실험을 하고 보고할 것이다.다음까지.

리소스

  • 동물 아이콘은 이 놀라운 창조자 사이트에서 나온 것이다:
  • 배경 이미지 소스: https://kenney.nl/
  • https://www.pixilart.com/art/pixel-farm-bb3c119b728eafdhttps://github.com/cqfd/quidproquo
  • 에서 PDA 구현에 대한 자세한 내용
  • https://github.com/project-serum/anchor/tree/master/tests/escrow
  • 좋은 웹페이지 즐겨찾기