액세스 프로토콜 V2의 온체인 로열티 수수료

곧 액세스 프로토콜 V2 온체인 프로그램에 구현될 로열티 수수료에 대해 알아보세요.

액세스 프로토콜
Access Protocol
9 min readMar 22, 2024

--

블라드(Vlad)는 액세스 프로토콜의 풀 스택 소프트웨어 엔지니어입니다. 엑스(트위터) 또는 이메일을 통해 블라드에게 연락하실 수 있습니다.

액세스 프로토콜 V2에 도입되는 중요한 새 기능 중 하나는 로열티와 추천 링크입니다. 이를 통해 사용자는 친구와 팔로워를 초대하여 추가 보상을 받을 수 있습니다.

목표

저희의 주요 목표는 새로운 사람들을 액세스 플랫폼으로 데려오는 사용자들에게 보상을 제공하는 온체인 메커니즘을 만드는 것이었습니다. 조건은 다음과 같습니다.

  • 프로토콜 인플레이션은 동일하게 유지하면서, 로열티 토큰을 새로 발행하지 않아야 합니다.
  • 로열티 수수료는 보편적이어야 합니다. 풀 소유자뿐만 아니라 초대된 사용자도 로열티를 지불해야 합니다.
  • 로열티 비율과 로열티가 지급되는 기간을 구성할 수 있는 방법이 있어야 합니다.
  • 로열티 지불 사기를 당한 사용자를 도울 수 있는 간단한 메커니즘이 있어야 합니다.
  • 초대를 수락하는 방법은 링크를 클릭하는 것처럼 간단해야 합니다.

해결 방법

앞서 언급한 모든 사항을 고려했을 때 저희는 다음과 같은 솔루션을 사용하기로 결정했습니다.

  • 로열티를 지불해야 하는 각 사용자에 대해 온체인에 로열티 계정 PDA생성합니다. 이 계정에는 수수료 계산에 필요한 모든 변수가 포함됩니다.
  • 로열티는 초대된 사용자가 보상을 청구할 때마다 계산하여 지급합니다. 로열티 비율에 따라 해당 사용자 보상에서 공제한 뒤, 초대한 지갑으로 전송합니다. 사용자 보상은 락업, 영구 락업 토큰 또는 풀에서 발생합니다.
  • 로열티 계정을 생성한 사용자가 로열티 계정을 폐쇄하는 기능도 있습니다. 이는 실수로 초대를 수락한 사용자의 문제를 대비한 온체인 안전 장치입니다.

온체인 구현

앞서 설명한 모든 목표를 달성하기 위해 저희는 다음과 같은 구조의 새로운 온체인 PDA를 만드는 것부터 시작했습니다.

pub struct RoyaltyAccount {
/// Tag to easily distinguish PDA types
pub tag: Tag,

/// The address that paid for the creation of this PDA - to be able to return funds on closing
pub rent_payer: Pubkey,

/// The address that has to pay royalties from all their claims
pub royalty_payer: Pubkey,

/// The address that collects the royalties
pub recipient_ata: Pubkey,

/// The date after which the royalties are not paid anymore
pub expiration_date: u64,

/// The royalty basis points (i.e 1% = 100) going to the recommender
pub royalty_basis_points: u16,
}

보시다시피 이 계정은 로열티 계산에 필요한 모든 정보와 만료일을 포함하고 있습니다.

로열티 계정 생성 방법은 간단합니다. 계정을 sanitize한 다음 로열티 지급자의 공개 키에서 파생된 키로 새 PDA를 생성하기만 하면 됩니다. 이 명령에는 다음 매개 변수가 필요합니다.

  • 로열티 기준 포인트
  • 만료 날짜
  • ACS 보상을 받아야 하는 ATA

전체 코드는 여기에서 확인할 수 있습니다.

다른 쪽에는 로열티 계정 PDA를 해지하는 방법이 있습니다. 이렇게 하면 계정을 해지하고, 지불된 모든 SOL 수수료를 원래 수수료 납부자에게 이체합니다. 전체 코드는 여기에서 확인할 수 있습니다.

더 흥미로운 부분은 청구 시 수수료가 실제로 지급되는지 확인하는 것입니다. 모든 청구 지침에 이 두 계정을 추가하여 가능한 로열티 요구 사항에 대한 정보를 전달합니다.

/// The owner's royalty split account to check if royalties need to be paid
pub owner_royalty_account: &'a T,

/// The royalty ATA account
#[cons(writable)]
pub royalty_ata: Option<&'a T>,

보시다시피 두 번째 계정은 선택 사항이며, owner_royalty_account 가 존재하는 경우에만 로열티 지급을 위해 필요합니다.

계정이 존재하고 만료되지 않았는지 확인하기 위해 모든 청구 지침에 사용되는 다음 함수를 구현했습니다.

///  This function checks if there is an existing royalty account.
/// Checks the relationship between the appropriate royalty account and the royalty ATA
/// Returns the royalty account data if it exists. Otherwise returns None.
pub fn retrieve_royalty_account(
royalty_account: &AccountInfo,
royalty_ata: Option<&AccountInfo>,
) -> Result<Option<RoyaltyAccount>, ProgramError> {
if royalty_account.data_is_empty() {
return Ok(None);
}

let royalty_account_data = RoyaltyAccount::from_account_info(royalty_account)?;
if royalty_account_data.expiration_date < Clock::get()?.unix_timestamp as u64 {
return Ok(None); // Royalty account has expired - no royalty split is applicable
}

if royalty_ata.is_none() {
return Err(AccessError::RoyaltyAtaNotProvided.into());
}

check_account_owner(
royalty_ata.unwrap(),
&spl_token::ID,
AccessError::WrongOwner,
)?;

check_account_key(
royalty_ata.unwrap(),
&royalty_account_data.recipient_ata,
AccessError::RoyaltyAtaNotDeterministic,
)?;

Ok(Some(royalty_account_data))
}

이 함수는 제공된 계정이 올바른지 확인하고, 올바른 경우 로열티 계정 또는 존재하지 않는 경우 None을 반환합니다.

그러면 다음과 같이 보상 분할을 계산하면 됩니다.

// Calculate the rewards (checks if the pool is cranked as well)
let mut reward = [...]

// split the rewards if there is a royalty account
let mut royalty_amount = 0;
if let Some(royalty_account) = royalty_account_data {
royalty_amount = royalty_account.calculate_royalty_amount(reward)?;
reward = reward.checked_sub(royalty_amount).ok_or(AccessError::Overflow)?;
}

그리고 해당 계정으로 지급합니다. 청구 지침의 전체 구현은 여기에서 확인할 수 있습니다.

한 가지 참고할 사항은 액세스 프로토콜 V2는 앵커를 사용하지 않는다는 것입니다. 그 이유는 이 프로그램이 앵커 프레임워크 이전에 만들어졌고, V2는 단지 확장에 불과했기에 완전히 다시 작성하지 않기로 결정했기 때문입니다.

프론트엔드 구현

이제 모든 온체인 로직을 갖추었으므로, 이를 FE에서 구현하는 가장 편리한 방법을 결정할 수 있습니다. 저희는 아래와 같이 구현합니다.

1. 모든 사용자에게는 초대 링크를 생성하는 데 사용하는 고유 ID가 있습니다. 이 링크는 다음과 같은 형태입니다.

https://hubv2.accessprotocol.co/invite/cb7f357bbcae610cd9b5f351824ddd89

2. 누군가 이 링크를 클릭하면 링크에 있는 ID에서 초대자의 공개 키를 검색하여 로컬 저장소에 기록합니다. 그런 다음 사용자를 로그인 페이지로 자동 전달합니다.

3. 새 사용자가 스테이킹하거나 풀을 생성하면 로컬 저장소를 확인하고 값이 있으면 블록체인에 전송하는 트랜잭션에 추가 인스트럭션을 추가합니다. 이 인스트럭션은 이전 섹션에서 보셨던 것처럼 적절한 로열티 계정을 생성합니다.

이게 전부입니다. 초대된 사용자가 추가적으로 해야 할 행동은 없습니다.

결론

액세스 프로토콜 V2에서 새로 구현된 로열티 계정을 통해 사용자가 친구와 팔로워를 플랫폼에 초대하도록 인센티브를 제공할 수 있습니다. 초대를 수락한 모든 사용자는 자신의 프로토콜 보상에서 1년간 10%의 로열티를 초대한 사람에게 지급하게 됩니다.

이 기능은 새로운 애플리케이션과 함께 곧 출시될 예정이니 기대해 주세요.

--

--

액세스 프로토콜
Access Protocol

전세계 모든 디지털 콘텐츠 크리에이터를 위한 새로운 수익 창출 레이어 https://accessprotocol.co