• 沒有找到結果。

第三章 金融 KYC 平台系統架構

3.4 Smart Contract 設計

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

36

圖 3.1 金融 KYC 平台聯盟鏈架構示意圖 資料來源:本研究整理

3.4 Smart Contract 設計

本研究的聯盟鏈是使用 ethereum homestead 版本,smart contract 是透過 solidity 的語言進行開發。

另外,本研究的 KYC 資料,是以富邦投信之”客戶投資適性分析表及風險預 告書”為範本做一個展示,並假設所有聯盟鏈中各銀行的 KYC 資料格式都是標準 一樣的。將其包含的 KYC 資訊,原始資料存放在銀行,而 Hash/簽章等相關的 資料放置於區塊鏈中以方便 Dapp 進行資料的比對。

底下為此風險預告書之原始資料:

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

37

圖 3.2 富邦投信客戶投資適性分析表及風險預告書(一) 資料來源:富邦金控網站”

https://www.fubon.com/asset-management/download/download_asset-management/2 0160301-03.pdf”

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

38

圖 3.3 富邦投信客戶投資適性分析表及風險預告書(二) 資料來源:富邦金控網站”

https://www.fubon.com/asset-management/download/download_asset-management/2 0160301-03.pdf”

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

39

根據以上的風險預告書原始資料,共有 27 個 KYC 的屬性。本研究在 smart contract(solidity)上針對每一筆 KYC 屬性設計其儲存及異動架構範例如下圖說明。

以姓名(name)屬性為例,姓名屬性會有一個 structure 來儲存其附屬的屬性資料,

分別記錄 1. 姓名的 HASH 值(hash_value) 2. 姓名屬性的註冊銀行(owner_of_bank) 3. 姓名屬性註冊銀行針對該屬性 hash 值,用其私鑰的簽章(digital_sig) 4. 是否允 許其他銀行查詢(queriable) 等四個資訊。而此姓名屬性(name)會透過 solidity 的 mapping 功能,以使用者的身分證/統編資料的 hash 資訊,透過 name_mapping 在不同使用者間指向到正確使用者的 structure 資料。而要異動姓名屬性時,必須 透過姓名異動的獨立函式(set_name)來異動,並在此函式的參數中,帶入使用者 身分證/統編、hash 值、註冊銀行、簽章資訊、是否同意存取等資訊,來對此姓 名屬性裡的相關附屬屬性做資料變更,在函式最後,會執行一個事件(event)宣告,

告知 ethereum 有一個事件發生,並在事件中附加使用者 id hash,以及式執行什 麼異動(set_name)以及是那間註冊銀行(owner_of_bank)異動的資訊,此事件後續 能夠做為是否要讓此平台進行主動的 KYC 同步動作的參考。

圖 3.4 智慧合約 KYC 資料架構圖範例,以姓名(name)為例 資料來源:本研究整理

在實作後發現,ethereum 的 smart contract 對於 contract 的裡頭變數及函數傳遞的 參數數量大小有其限制,而且當變數的屬性若為 string 屬性,會比使用 bytes32 宣告要花費更多的 gas 去建立 contract。若塞入所有的 KYC 欄位,則在建立該 contract 時會發生問題,導致該 contract 無法使用,由於本研究的假設情境是在 聯盟鏈中執行,並不需要考慮 gas 的使用狀況,可以在 Dapp 程式中給予足夠的

struct p_income_monthly { #客戶個人月收入

string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct p_home_income_yearly { #客戶家庭月收入 string hash_value;

struct c_business_type { #法人行業別

string hash_value;

string owner_of_bank;

string digital_sig;

mapping (bytes32 => exist) public exist_mapping;

mapping (bytes32 => name) public name_mapping;

mapping (bytes32 => phone) public phone_mapping;

mapping (bytes32 => id) public id_mapping;

mapping (bytes32 => p_education) public p_education_mapping;

mapping (bytes32 => p_birthday) public p_birthday_mapping;

mapping (bytes32 => p_career) public p_career_mapping;

mapping (bytes32 => p_income_monthly) public p_income_monthly_mapping;

mapping (bytes32 => p_home_income_yearly) public p_home_income_yearly_mapping;

mapping (bytes32 => p_insurance) public p_insurance_mapping;

mapping (bytes32 => c_business_type) public c_business_type_mapping;

3. 變更每個 KYC 屬性的 structure 時,透過不同的 function 達成,每個變更最 後 trigger 一個智慧合約的 event,廣播有 KYC 屬性異動事件

function set_total_digest(string customerid, string value, string owner_of_bank) { total_digest_mapping[sha256(customerid)].value = value;

total_digest_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

SETEVENT(sha256(customerid), "set_total_digest", owner_of_bank);

}

function set_exist(string customerid, bool value, string owner_of_bank ) { exist_mapping[sha256(customerid)].value = value;

exist_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

SETEVENT(sha256(customerid), "set_exist", owner_of_bank);

}

function set_name(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

name_mapping[sha256(customerid)].hash_value = hash_value;

name_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

name_mapping[sha256(customerid)].digital_sig = digital_sig;

name_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_name", owner_of_bank);

}

function set_phone(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

phone_mapping[sha256(customerid)].hash_value = hash_value;

phone_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

phone_mapping[sha256(customerid)]. digital_sig = digital_sig;

phone_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_phone", owner_of_bank);

}

function set_id(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

id_mapping[sha256(customerid)].hash_value = hash_value;

id_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

id_mapping[sha256(customerid)]. digital_sig = digital_sig;

id_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_id", owner_of_bank);

}

function set_p_education(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_education_mapping[sha256(customerid)].hash_value = hash_value;

p_education_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_education_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_education_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_education", owner_of_bank);

}

function set_p_birthday(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_birthday_mapping[sha256(customerid)].hash_value = hash_value;

p_birthday_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_birthday_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_birthday_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_birthday", owner_of_bank);

}

function set_p_career(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_career_mapping[sha256(customerid)].hash_value = hash_value;

p_career_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_career_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_career_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_career", owner_of_bank);

}

function set_p_income_monthly(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_income_monthly_mapping[sha256(customerid)].hash_value = hash_value;

p_income_monthly_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_income_monthly_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_income_monthly_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_income_monthly", owner_of_bank);

}

function set_p_home_income_yearly(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_home_income_yearly_mapping[sha256(customerid)].hash_value = hash_value;

p_home_income_yearly_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_home_income_yearly_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_home_income_yearly_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_home_income_yearly", owner_of_bank);

}

function set_p_insurance(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

p_insurance_mapping[sha256(customerid)].hash_value = hash_value;

p_insurance_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

p_insurance_mapping[sha256(customerid)]. digital_sig = digital_sig;

p_insurance_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_p_insurance", owner_of_bank);

}

function set_c_business_type(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_business_type_mapping[sha256(customerid)].hash_value = hash_value;

c_business_type_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_business_type_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_business_type_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_business_type", owner_of_bank);

}

struct c_income_monthly { #法人月營收

string hash_value;

struct investment_info_source { #客戶投資理財來源 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_source { #客戶所得與資金來源

string hash_value;

struct investment_knowledge_1 { #客戶投資知識專業能力一 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_knowledge_2 { #客戶投資知識專業能力二 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct funding_experience { #客戶投資基金經驗 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

mapping (bytes32 => c_org_type) public c_org_type_mapping;

mapping (bytes32 => c_capital) public c_capital_mapping;

mapping (bytes32 => c_income_monthly) public c_income_monthly_mapping;

mapping (bytes32 => c_over_25) public c_over_25_mapping;

mapping (bytes32 => c_professional_org) public c_professional_org_mapping;

mapping (bytes32 => investment_info_source) public investment_info_source_mapping;

mapping (bytes32 => investment_source) public investment_source_mapping;

mapping (bytes32 => investment_amount) public investment_amount_mapping;

mapping (bytes32 => investment_type) public investment_type_mapping;

mapping (bytes32 => investment_knowledge_1) public investment_knowledge_1_mapping;

mapping (bytes32 => investment_knowledge_2) public investment_knowledge_2_mapping;

mapping (bytes32 => funding_experience) public funding_experience_mapping;

function set_c_org_type(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_org_type_mapping[sha256(customerid)].hash_value = hash_value;

c_org_type_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_org_type_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_org_type_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_org_type", owner_of_bank);

}

function set_c_capital(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_capital_mapping[sha256(customerid)].hash_value = hash_value;

c_capital_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_capital_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_capital_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_capital", owner_of_bank);

}

function set_c_income_monthly(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_income_monthly_mapping[sha256(customerid)].hash_value = hash_value;

c_income_monthly_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_income_monthly_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_income_monthly_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_income_monthly", owner_of_bank);

}

function set_c_over_25(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_over_25_mapping[sha256(customerid)].hash_value = hash_value;

c_over_25_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_over_25_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_over_25_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_over_25", owner_of_bank);

}

function set_c_professional_org(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

c_professional_org_mapping[sha256(customerid)].hash_value = hash_value;

c_professional_org_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

c_professional_org_mapping[sha256(customerid)]. digital_sig = digital_sig;

c_professional_org_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_c_professional_org", owner_of_bank);

}

function set_investment_info_source(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_info_source_mapping[sha256(customerid)].hash_value = hash_value;

investment_info_source_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_info_source_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_info_source_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_info_source", owner_of_bank);

}

function set_investment_source(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_source_mapping[sha256(customerid)].hash_value = hash_value;

investment_source_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_source_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_source_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_source", owner_of_bank);

}

function set_investment_amount(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_amount_mapping[sha256(customerid)].hash_value = hash_value;

investment_amount_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_amount_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_amount_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_amount", owner_of_bank);

}

function set_investment_type(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_type_mapping[sha256(customerid)].hash_value = hash_value;

investment_type_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_type_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_type_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_type", owner_of_bank);

}

function set_investment_knowledge_1(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_knowledge_1_mapping[sha256(customerid)].hash_value = hash_value;

investment_knowledge_1_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_knowledge_1_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_knowledge_1_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_knowledge_1", owner_of_bank);

}

function set_investment_knowledge_2(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_knowledge_2_mapping[sha256(customerid)].hash_value = hash_value;

investment_knowledge_2_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_knowledge_2_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_knowledge_2_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_knowledge_2", owner_of_bank);

function set_funding_experience(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

funding_experience_mapping[sha256(customerid)].hash_value = hash_value;

funding_experience_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

funding_experience_mapping[sha256(customerid)]. digital_sig = digital_sig;

funding_experience_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_funding_experience", owner_of_bank);

}

 Contract C: (放置 1/3 的 KYC 欄位、不再分段說明) struct investment_experience { #客戶過往投資經驗 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_purpose { #客戶投資目的 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_favorite { #客戶基金偏好 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_risk_taken { #客戶投資風險承受度 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

struct investment_of_income { #客戶資金操作 string hash_value;

string owner_of_bank;

string digital_sig;

bool queriable;

}

mapping (bytes32 => investment_experience) public investment_experience_mapping;

mapping (bytes32 => investment_purpose) public investment_purpose_mapping;

mapping (bytes32 => investment_favorite) public investment_favorite_mapping;

mapping (bytes32 => investment_risk_taken) public investment_risk_taken_mapping;

mapping (bytes32 => investment_of_income) public investment_of_income_mapping;

function set_investment_experience(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_experience_mapping[sha256(customerid)].hash_value = hash_value;

investment_experience_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_experience_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_experience_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_experience", owner_of_bank);

}

function set_investment_purpose(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_purpose_mapping[sha256(customerid)].hash_value = hash_value;

investment_purpose_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_purpose_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_purpose_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_purpose", owner_of_bank);

}

function set_investment_favorite(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_favorite_mapping[sha256(customerid)].hash_value = hash_value;

investment_favorite_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_favorite_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_favorite_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_favorite", owner_of_bank);

}

function set_investment_risk_taken(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_risk_taken_mapping[sha256(customerid)].hash_value = hash_value;

investment_risk_taken_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_risk_taken_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_risk_taken_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_risk_taken", owner_of_bank);

}

function set_investment_of_income(string customerid, string hash_value, string owner_of_bank, string digital_sig, bool queriable ) {

investment_of_income_mapping[sha256(customerid)].hash_value = hash_value;

investment_of_income_mapping[sha256(customerid)].owner_of_bank = owner_of_bank;

investment_of_income_mapping[sha256(customerid)]. digital_sig = digital_sig;

investment_of_income_mapping[sha256(customerid)].queriable = queriable;

SETEVENT(sha256(customerid), "set_investment_of_income", owner_of_bank);

}

meteor:PRIMARY> db.colKycinfo_A.find().pretty() {

"_id" : "K64c873ia9iEr7tLi", #Mongo DB 的 index ID

"id" : "N1234", #客戶的身分證號/統一編號

"shaid" : #客戶 id 的 Hash 值

"0xd4d4f8f5a75bbee10f9e2237f1527dc811918991c7245cdf69d042acc763e786"

"name" : "Jason1", #客戶名稱

相關文件